/** @file
Private include file for IsaFloppyPei PEIM.

Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef _RECOVERY_FLOPPY_H_
#define _RECOVERY_FLOPPY_H_

#include <Ppi/BlockIo.h>

#include <Library/DebugLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/ReportStatusCodeLib.h>
#include <Library/TimerLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>

#include "Fdc.h"


//
// Some PC AT Compatible Device definitions
//
//
// 8237 DMA registers
//
#define R_8237_DMA_BASE_CA_CH0                    0x00
#define R_8237_DMA_BASE_CA_CH1                    0x02
#define R_8237_DMA_BASE_CA_CH2                    0x04
#define R_8237_DMA_BASE_CA_CH3                    0xd6
#define R_8237_DMA_BASE_CA_CH5                    0xc4
#define R_8237_DMA_BASE_CA_CH6                    0xc8
#define R_8237_DMA_BASE_CA_CH7                    0xcc

#define R_8237_DMA_BASE_CC_CH0                    0x01
#define R_8237_DMA_BASE_CC_CH1                    0x03
#define R_8237_DMA_BASE_CC_CH2                    0x05
#define R_8237_DMA_BASE_CC_CH3                    0xd7
#define R_8237_DMA_BASE_CC_CH5                    0xc6
#define R_8237_DMA_BASE_CC_CH6                    0xca
#define R_8237_DMA_BASE_CC_CH7                    0xce

#define R_8237_DMA_MEM_LP_CH0                     0x87
#define R_8237_DMA_MEM_LP_CH1                     0x83
#define R_8237_DMA_MEM_LP_CH2                     0x81
#define R_8237_DMA_MEM_LP_CH3                     0x82
#define R_8237_DMA_MEM_LP_CH5                     0x8B
#define R_8237_DMA_MEM_LP_CH6                     0x89
#define R_8237_DMA_MEM_LP_CH7                     0x8A


#define R_8237_DMA_COMMAND_CH0_3                  0x08
#define R_8237_DMA_COMMAND_CH4_7                  0xd0
#define   B_8237_DMA_COMMAND_GAP                  0x10
#define   B_8237_DMA_COMMAND_CGE                  0x04


#define R_8237_DMA_STA_CH0_3                      0x09
#define R_8237_DMA_STA_CH4_7                      0xd2

#define R_8237_DMA_WRSMSK_CH0_3                   0x0a
#define R_8237_DMA_WRSMSK_CH4_7                   0xd4
#define   B_8237_DMA_WRSMSK_CMS                   0x04


#define R_8237_DMA_CHMODE_CH0_3                   0x0b
#define R_8237_DMA_CHMODE_CH4_7                   0xd6
#define   V_8237_DMA_CHMODE_DEMAND                0x00
#define   V_8237_DMA_CHMODE_SINGLE                0x40
#define   V_8237_DMA_CHMODE_CASCADE               0xc0
#define   B_8237_DMA_CHMODE_DECREMENT             0x20
#define   B_8237_DMA_CHMODE_INCREMENT             0x00
#define   B_8237_DMA_CHMODE_AE                    0x10
#define   V_8237_DMA_CHMODE_VERIFY                0
#define   V_8237_DMA_CHMODE_IO2MEM                0x04
#define   V_8237_DMA_CHMODE_MEM2IO                0x08

#define R_8237_DMA_CBPR_CH0_3                     0x0c
#define R_8237_DMA_CBPR_CH4_7                     0xd8

#define R_8237_DMA_MCR_CH0_3                      0x0d
#define R_8237_DMA_MCR_CH4_7                      0xda

#define R_8237_DMA_CLMSK_CH0_3                    0x0e
#define R_8237_DMA_CLMSK_CH4_7                    0xdc

#define R_8237_DMA_WRMSK_CH0_3                    0x0f
#define R_8237_DMA_WRMSK_CH4_7                    0xde

///
/// ISA memory range
///
#define ISA_MAX_MEMORY_ADDRESS  0x1000000

//
// Macro for time delay & interval
//
#define STALL_1_SECOND           1000000
#define STALL_1_MSECOND          1000
#define FDC_CHECK_INTERVAL       50

#define FDC_SHORT_DELAY          50
#define FDC_MEDIUM_DELAY         100
#define FDC_LONG_DELAY           4000
#define FDC_RESET_DELAY          2000
#define FDC_RECALIBRATE_DELAY    250000

typedef enum {
  FdcType360K360K  = 0,
  FdcType360K1200K,
  FdcType1200K1200K,
  FdcType720K720K,
  FdcType720K1440K,
  FdcType1440K1440K,
  FdcType720K2880K,
  FdcType1440K2880K,
  FdcType2880K2880K
} FDC_DISKET_TYPE;

typedef struct {
  UINT8 Register;
  UINT8 Value;
} PEI_DMA_TABLE;

typedef struct {
  UINT8                      DevPos;
  UINT8                      Pcn;
  BOOLEAN                    MotorOn;
  BOOLEAN                    NeedRecalibrate;
  FDC_DISKET_TYPE            Type;
  EFI_PEI_BLOCK_IO_MEDIA     MediaInfo;
} PEI_FLOPPY_DEVICE_INFO;

#define FDC_BLK_IO_DEV_SIGNATURE  SIGNATURE_32 ('F', 'b', 'i', 'o')

typedef struct {
  UINTN                           Signature;
  EFI_PEI_RECOVERY_BLOCK_IO_PPI   FdcBlkIo;
  EFI_PEI_PPI_DESCRIPTOR          PpiDescriptor;
  UINTN                           DeviceCount;
  PEI_FLOPPY_DEVICE_INFO          DeviceInfo[2];
} FDC_BLK_IO_DEV;

#define PEI_RECOVERY_FDC_FROM_BLKIO_THIS(a) CR (a, FDC_BLK_IO_DEV, FdcBlkIo, FDC_BLK_IO_DEV_SIGNATURE)

//
// PEI Recovery Block I/O PPI
//

/**
  Get the number of FDC devices.

  This function implements EFI_PEI_RECOVERY_BLOCK_IO_PPI.GetNumberOfBlockDevices.
  It get the number of FDC devices in the system.

  @param  PeiServices           An indirect pointer to the PEI Services Table published by the PEI Foundation.
  @param  This                  Pointer to this PPI instance.
  @param  NumberBlockDevices    Pointer to the the number of FDC devices for output.

  @retval EFI_SUCCESS           Number of FDC devices is retrieved successfully.
  @retval EFI_INVALID_PARAMETER Parameter This is NULL.

**/
EFI_STATUS
EFIAPI
FdcGetNumberOfBlockDevices (
  IN   EFI_PEI_SERVICES                  **PeiServices,
  IN   EFI_PEI_RECOVERY_BLOCK_IO_PPI     *This,
  OUT  UINTN                             *NumberBlockDevices
  );

/**
  Get the specified media information.

  This function implements EFI_PEI_RECOVERY_BLOCK_IO_PPI.GetBlockDeviceMediaInfo.
  It gets the specified media information.

  @param  PeiServices           An indirect pointer to the PEI Services Table published by the PEI Foundation.
  @param  This                  Pointer to this PPI instance.
  @param  DeviceIndex           Index of FDC device to get information.
  @param  MediaInfo             Pointer to the media info buffer for output.

  @retval EFI_SUCCESS           Number of FDC devices is retrieved successfully.
  @retval EFI_INVALID_PARAMETER Parameter This is NULL.
  @retval EFI_INVALID_PARAMETER Parameter MediaInfo is NULL.
  @retval EFI_INVALID_PARAMETER DeviceIndex is not valid.
  @retval EFI_DEVICE_ERROR      FDC device does not exist or has errors.

**/
EFI_STATUS
EFIAPI
FdcGetBlockDeviceMediaInfo (
  IN   EFI_PEI_SERVICES                     **PeiServices,
  IN   EFI_PEI_RECOVERY_BLOCK_IO_PPI        *This,
  IN   UINTN                                DeviceIndex,
  OUT  EFI_PEI_BLOCK_IO_MEDIA               *MediaInfo
  );

/**
  Get the requested number of blocks from the specified FDC device.

  This function implements EFI_PEI_RECOVERY_BLOCK_IO_PPI.ReadBlocks.
  It reads the requested number of blocks from the specified FDC device.

  @param  PeiServices           An indirect pointer to the PEI Services Table published by the PEI Foundation.
  @param  This                  Pointer to this PPI instance.
  @param  DeviceIndex           Index of FDC device to get information.
  @param  StartLba              The start LBA to read from.
  @param  BufferSize            The size of range to read.
  @param  Buffer                Buffer to hold the data read from FDC.

  @retval EFI_SUCCESS           Number of FDC devices is retrieved successfully.
  @retval EFI_INVALID_PARAMETER Parameter This is NULL.
  @retval EFI_INVALID_PARAMETER Parameter Buffer is NULL.
  @retval EFI_INVALID_PARAMETER Parameter BufferSize cannot be divided by block size of FDC device.
  @retval EFI_NO_MEDIA          No media present.
  @retval EFI_DEVICE_ERROR      FDC device has error.
  @retval Others                Fail to read blocks.

**/
EFI_STATUS
EFIAPI
FdcReadBlocks (
  IN   EFI_PEI_SERVICES                  **PeiServices,
  IN   EFI_PEI_RECOVERY_BLOCK_IO_PPI     *This,
  IN   UINTN                             DeviceIndex,
  IN   EFI_PEI_LBA                       StartLba,
  IN   UINTN                             BufferSize,
  OUT  VOID                              *Buffer
  );

#endif
